﻿/**************************************************************
*作者：Leon
*创建时间：2022/4/5 16:12:18
**************************************************************/
using System.Windows.Controls.Primitives;
using System.Windows;
namespace Lad.DrawProject.Controls;

public class ResizeThumb : Thumb
{
    private IBaseCanvasViewModel? serviceProvider;

    public IBaseCanvasViewModel ServiceProvider
    {
        get { return serviceProvider ??= (IBaseCanvasViewModel)this.GetBaseCanvas()!.DataContext; }
    }
    public ResizeThumb()
    {
        base.DragDelta += new DragDeltaEventHandler(ResizeThumb_DragDelta);
        base.DragStarted += ResizeThumb_DragStarted;
        base.DragCompleted += ResizeThumb_DragCompleted;
    }

    private List<SelectableItemViewModelBase>? designerItems;


    private void ResizeThumb_DragStarted(object sender, DragStartedEventArgs e)
    {
        if (this.DataContext is DesignerItemViewModelBase designerItem)
        {
            if (designerItem.IsSelected)
            {
                designerItems = ServiceProvider.SelectedItems.ToList();
                foreach (var item in designerItems)//设置撤回操作的历史值
                {
                    item.SetOldValue(new() {
                        (item.Width, nameof(item.Width)),
                        (item.Height, nameof(item.Height))
                    });
                }
                e.Handled = true;
            }
            else
            {
                designerItems = null;
            }
        }
    }

    private void ResizeThumb_DragCompleted(object sender, DragCompletedEventArgs e)
    {
        if (designerItems != null)
        {
            foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
            {
                item.RaiseItemWidthHeight();
            }

            e.Handled = true;
        }
    }


    void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
    {
        if (designerItems != null && ServiceProvider != null)
        {
            double dragDeltaVertical, dragDeltaHorizontal, scale;

            CalculateDragLimits(designerItems.OfType<DesignerItemViewModelBase>(), out double minLeft, out double minTop,
                                out double minDeltaHorizontal, out double minDeltaVertical);

            foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
            {
                if (item != null && item.ParentId == Guid.Empty)
                {
                    switch (base.VerticalAlignment)
                    {
                        case VerticalAlignment.Bottom:
                            dragDeltaVertical = Math.Min(-e.VerticalChange, minDeltaVertical);
                            scale = (item.Height - dragDeltaVertical) / item.Height;
                            DragBottom(scale, item, ServiceProvider.SelectionService);
                            break;
                        case VerticalAlignment.Top:
                            double top = item.Top;
                            dragDeltaVertical = Math.Min(Math.Max(-minTop, e.VerticalChange), minDeltaVertical);
                            scale = (item.Height - dragDeltaVertical) / item.Height;
                            DragTop(scale, item, ServiceProvider.SelectionService);
                            break;
                        default:
                            break;
                    }

                    switch (base.HorizontalAlignment)
                    {
                        case HorizontalAlignment.Left:
                            double left = item.Left;
                            dragDeltaHorizontal = Math.Min(Math.Max(-minLeft, e.HorizontalChange), minDeltaHorizontal);
                            scale = (item.Width - dragDeltaHorizontal) / item.Width;
                            DragLeft(scale, item, ServiceProvider.SelectionService);
                            break;
                        case HorizontalAlignment.Right:
                            dragDeltaHorizontal = Math.Min(-e.HorizontalChange, minDeltaHorizontal);
                            scale = (item.Width - dragDeltaHorizontal) / item.Width;
                            DragRight(scale, item, ServiceProvider.SelectionService);
                            break;
                        default:
                            break;
                    }
                }
            }

            e.Handled = true;
        }
    }

    #region Helper methods

    private void DragLeft(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
    {
        IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();

        double groupLeft = item.Left + item.Width;
        foreach (DesignerItemViewModelBase groupItem in groupItems)
        {
            double groupItemLeft = groupItem.Left;
            double delta = (groupLeft - groupItemLeft) * (scale - 1);
            groupItem.Left = groupItemLeft - delta;
            groupItem.Width *= scale;
        }
    }

    private void DragTop(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
    {
        IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
        double groupBottom = item.Top + item.Height;
        foreach (DesignerItemViewModelBase groupItem in groupItems)
        {
            double groupItemTop = groupItem.Top;
            double delta = (groupBottom - groupItemTop) * (scale - 1);
            groupItem.Top = groupItemTop - delta;
            groupItem.Height *= scale;
        }
    }

    private void DragRight(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
    {
        IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();

        double groupLeft = item.Left;
        foreach (DesignerItemViewModelBase groupItem in groupItems)
        {
            double groupItemLeft = groupItem.Left;
            double delta = (groupItemLeft - groupLeft) * (scale - 1);

            groupItem.Left = groupItemLeft + delta;
            groupItem.Width *= scale;
        }
    }

    private void DragBottom(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
    {
        IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
        double groupTop = item.Top;
        foreach (DesignerItemViewModelBase groupItem in groupItems)
        {
            double groupItemTop = groupItem.Top;
            double delta = (groupItemTop - groupTop) * (scale - 1);

            groupItem.Top = groupItemTop + delta;
            groupItem.Height *= scale;
        }
    }

    private void CalculateDragLimits(IEnumerable<DesignerItemViewModelBase> selectedItems, out double minLeft, out double minTop, out double minDeltaHorizontal, out double minDeltaVertical)
    {
        minLeft = double.MaxValue;
        minTop = double.MaxValue;
        minDeltaHorizontal = double.MaxValue;
        minDeltaVertical = double.MaxValue;

        // drag limits are set by these parameters: canvas top, canvas left, minHeight, minWidth
        // calculate min value for each parameter for each item
        foreach (DesignerItemViewModelBase item in selectedItems)
        {
            double left = item.Left;
            double top = item.Top;

            minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
            minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);

            minDeltaVertical = Math.Min(minDeltaVertical, 10);
            minDeltaHorizontal = Math.Min(minDeltaHorizontal, 10);
        }
    }

    #endregion
}
